home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / GUSI / GUSIAppleTalk.cp < prev    next >
Text File  |  1993-12-30  |  18KB  |  924 lines

  1. /*********************************************************************
  2. Project    :    GUSI                    -    Grand Unified Socket Interface
  3. File        :    GUSIAppleTalk.cp    -    Appletalk Sockets
  4. Author    :    Matthias Neeracher
  5. Started    :    03May92                                Language    :    MPW C/C++
  6. Modified    :    10May92    MN    ADSPStreams
  7.                 12May92    MN    NBP stuff
  8.                 18May92    MN    Basic functions work
  9.                 18May92    MN    Out of band data
  10.                 13Jul92    MN    Make AppleTalkSockets available to other socket classes.
  11.                 21Jul92    MN    Support symbolic addresses
  12.                 26Jul92    MN    Error in using memccpy()
  13.                 28Jul92    MN    Separate creating symaddrs from registering them
  14.                 10Aug92    MN    Improve select()
  15.                 07Sep92    MN    Implement ioctl()
  16.                 13Sep92    MN    Always complete write
  17.                 05Oct92    MN    I was a teenage NBP werewolf
  18.                 07Dec92    MN    Use flags
  19.                 17Jan93    MN    Handle user interrupts more carefully.
  20.                 07Feb93    MN    New configuration technique
  21.                 01Sep93    MN    Throw out nonbreaking spaces
  22.                 17Nov93    MN    Delay opening AppleTalk services
  23.                 30Dec93    MN    Fiddle with select()
  24. Last        :    30Dec93
  25. *********************************************************************/
  26.  
  27. #include "GUSI_P.h"
  28.  
  29. #include <Errors.h>
  30. #include <ADSP.h>
  31. #include <Devices.h>
  32. #include <GestaltEqu.h>
  33. #include <PLStringFuncs.h>
  34.  
  35. #include <Strings.h>
  36.  
  37. #include <sys/types.h>
  38.  
  39. class AtlkSymAddr;
  40.  
  41. class AppleTalkSocketDomain : public SocketDomain {
  42.     short                        dspRefNum;
  43.     
  44.     void                        DoMPPOpen();
  45. public:
  46.     AppleTalkSocketDomain();
  47.     
  48.     AddrBlock                node;
  49.     
  50.                 short            GetDSP();        
  51.                 Boolean        Validate();
  52.     virtual    Socket *     socket(int type, short protocol);
  53.     virtual int choose(
  54.                         int         type, 
  55.                         char *     prompt, 
  56.                         void *     constraint,        
  57.                         int         flags,
  58.                          void *     name, 
  59.                         int *     namelen);
  60. };
  61.  
  62. class AppleTalkSocket : public Socket    {        // That's what this file's all about
  63.     friend class AppleTalkSocketDomain;
  64. protected:
  65.     Boolean            nonblocking;
  66.     Boolean            ownSocket;
  67.     Boolean            readShutDown;
  68.     Boolean            writeShutDown;
  69.     u_char            socket;
  70.     AddrBlock        peer;
  71.     AtlkSymAddr *    symaddr;
  72.  
  73.                     AppleTalkSocket(u_char sock = 0);
  74.  
  75.     virtual         ~AppleTalkSocket();
  76. public:
  77.     virtual int    bind(void * name, int namelen);
  78.     virtual int getsockname(void * name, int * namelen);
  79.     virtual int getpeername(void *name, int *namelen);
  80.     virtual int    fcntl(unsigned int cmd, int arg);
  81.     virtual int    ioctl(unsigned int request, void *argp);
  82. };
  83.  
  84. struct ADSPSockBuffers {
  85.     enum {qSize    =    4150};
  86.  
  87.     u_char    attnBuf[attnBufSize];
  88.     u_char    sendBuf[qSize];
  89.     u_char    recvBuf[qSize];
  90. };
  91.  
  92. typedef ADSPSockBuffers * ADSPBufPtr;
  93.  
  94. class ADSPSocket : public AppleTalkSocket {
  95.     friend class AppleTalkSocketDomain;
  96.  
  97.                     ADSPSocket(u_char sock = 0);
  98.  
  99.     TRCCB    *        ccb;
  100.     DSPPBPtr        pb;
  101.     ADSPBufPtr    bufs;
  102.  
  103.     int            Init();
  104.     void            UnInit(Boolean abort);
  105.     Boolean        Waiting();
  106.     Boolean        Up();
  107. public:
  108.     virtual int listen(int qlen);
  109.     virtual int connect(void * address, int addrlen);
  110.     virtual Socket * accept(void * address, int * addrlen);
  111.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  112.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  113.     virtual int shutdown(int how);
  114.     virtual int    ioctl(unsigned int request, void *argp);
  115.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  116.  
  117.     virtual         ~ADSPSocket();
  118. };
  119.  
  120. class AtlkSymAddr {
  121.     struct NTE    {
  122.         Ptr            next;
  123.         AddrBlock    addr;
  124.         char            rsrv;
  125.         char            name;
  126.     };
  127.  
  128.     NTE *        nte;
  129.     Boolean    legit;
  130. public:
  131.     AtlkSymAddr(const EntityName & name);
  132.  
  133.     ~AtlkSymAddr();
  134.  
  135.     void Register(u_char socket);
  136. };
  137.  
  138. int AtlkLookup(const EntityName & name, AddrBlock * addr);
  139.  
  140. AppleTalkSocketDomain    AppleTalkSockets;
  141. const AddrBlock            NoFilter    =    {0, 0, 0};
  142.  
  143. /************************ AppleTalkSocket members ************************/
  144.  
  145. AppleTalkSocket::AppleTalkSocket(u_char sock)
  146. {
  147.     socket            =    sock;
  148.     ownSocket        =    !sock;
  149.     nonblocking        =    false;
  150.     readShutDown    =    false;
  151.     writeShutDown    =    false;
  152.     symaddr            =    nil;
  153.     peer                =    NoFilter;
  154. }
  155.  
  156. AppleTalkSocket::~AppleTalkSocket()
  157. {
  158.     if (socket && ownSocket)    {
  159.         MPPParamBlock    mpp;
  160.  
  161.         mpp.DDP.socket    =    socket;
  162.  
  163.         PCloseSkt(&mpp, false);
  164.     }
  165.  
  166.     if (symaddr)
  167.         delete symaddr;
  168. }
  169.  
  170. int AppleTalkSocket::fcntl(unsigned int cmd, int arg)
  171. {
  172.     switch (cmd)    {
  173.     case F_GETFL:
  174.         if (nonblocking)
  175.             return FNDELAY;
  176.         else
  177.             return 0;
  178.     case F_SETFL:
  179.         if (arg & FNDELAY)
  180.             nonblocking = true;
  181.         else
  182.             nonblocking = false;
  183.  
  184.         return 0;
  185.     default:
  186.         return GUSI_error(EOPNOTSUPP);
  187.     }
  188. }
  189.  
  190. int AppleTalkSocket::ioctl(unsigned int request, void *argp)
  191. {
  192.     switch (request)    {
  193.     case FIONBIO:
  194.         nonblocking    =    (Boolean) *(long *) argp;
  195.  
  196.         return 0;
  197.     default:
  198.         return GUSI_error(EOPNOTSUPP);
  199.     }
  200. }
  201.  
  202. int AppleTalkSocket::bind(void *sa_name, int)
  203. {
  204.  
  205.     switch (*(short *) sa_name)    {
  206.     case AF_APPLETALK:
  207.         {
  208.             struct sockaddr_atlk *    addr = (struct sockaddr_atlk *) sa_name;
  209.  
  210.             if (socket || !addr->addr.aSocket)
  211.                 return GUSI_error(EINVAL);
  212.  
  213.             socket        =    addr->addr.aSocket;
  214.             ownSocket    =    false;
  215.         }
  216.         break;
  217.     case ATALK_SYMADDR:
  218.         {
  219.             struct sockaddr_atlk_sym *    addr = (struct sockaddr_atlk_sym *) sa_name;
  220.  
  221.             symaddr        =    new AtlkSymAddr(addr->name);
  222.  
  223.             if (errno)    {
  224.                 delete symaddr;
  225.                 symaddr = nil;
  226.  
  227.                 return -1;
  228.             }
  229.         }
  230.         break;
  231.     default:
  232.         return GUSI_error(EAFNOSUPPORT);
  233.     }
  234.  
  235.     return 0;
  236. }
  237.  
  238. int AppleTalkSocket::getsockname(void *name, int *namelen)
  239. {
  240.     struct sockaddr_atlk    addr;
  241.  
  242.     addr.family            =    AF_APPLETALK;
  243.     addr.addr            =    AppleTalkSockets.node;
  244.     addr.addr.aSocket    =    socket;
  245.  
  246.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_atlk)));
  247.  
  248.     return 0;
  249. }
  250.  
  251. int AppleTalkSocket::getpeername(void *name, int *namelen)
  252. {
  253.     struct sockaddr_atlk    addr;
  254.  
  255.     if (!peer.aNet && !peer.aNode && !peer.aSocket)
  256.         return GUSI_error(ENOTCONN);
  257.  
  258.     addr.family            =    AF_APPLETALK;
  259.     addr.addr            =    peer;
  260.  
  261.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_atlk)));
  262.  
  263.     return 0;
  264. }
  265.  
  266. /********************* ADSPSocket members *********************/
  267.  
  268. ADSPSocket::ADSPSocket(u_char sock)
  269.     :    AppleTalkSocket(sock)
  270. {
  271.     ccb            =    nil;
  272.     pb                =    nil;
  273.     bufs             =    nil;
  274.  
  275.     if (!AppleTalkSockets.GetDSP())
  276.         GUSI_error(EPFNOSUPPORT);                    // Just an educated guess
  277. }
  278.  
  279. ADSPSocket::~ADSPSocket()
  280. {
  281.     UnInit(false);
  282. }
  283.  
  284. inline Boolean ADSPSocket::Waiting()
  285. {
  286.     return pb->ioResult == 1 && !(ccb->userFlags & (eClosed | eTearDown));
  287. }
  288.  
  289. inline Boolean ADSPSocket::Up()
  290. {
  291.     return !(ccb->userFlags & (eClosed | eTearDown));
  292. }
  293.  
  294. int ADSPSocket::listen(int)
  295. {
  296.     if (ccb)
  297.         return GUSI_error(EISCONN);
  298.  
  299.     ccb     =    new TRCCB;
  300.     if (!ccb)
  301.         goto memErrCCB;
  302.  
  303.     pb        =    new DSPParamBlock;
  304.     if (!pb)
  305.         goto memErrPB;
  306.  
  307.     pb->ioCRefNum                        =    AppleTalkSockets.GetDSP();
  308.     pb->csCode                            =    dspCLInit;
  309.     pb->u.initParams.ccbPtr            =    ccb;
  310.     pb->u.initParams.localSocket    =    socket;
  311.  
  312.     if (PBControlSync(ParmBlkPtr(pb)))
  313.         goto memErr;
  314.  
  315.     socket        =    pb->u.initParams.localSocket;
  316.  
  317.     if (symaddr)
  318.         symaddr->Register(socket);
  319.  
  320.     pb->csCode                                =    dspCLListen;
  321.     pb->ioCompletion                        =    nil;
  322.     pb->u.openParams.filterAddress    =    NoFilter;
  323.  
  324.     PBControlAsync(ParmBlkPtr(pb));
  325.  
  326.     return 0;
  327.  
  328. memErr:
  329.     delete pb;
  330.     pb    =    nil;
  331. memErrPB:
  332.     delete ccb;
  333.     ccb    =    nil;
  334. memErrCCB:
  335.     return GUSI_error(ENOMEM);
  336. }
  337.  
  338. int ADSPSocket::Init()
  339. {
  340.     if (ccb)
  341.         if (pb->csCode == dspOpen && pb->ioResult && pb->ioResult != 1)
  342.             return 0;                            // Second chance for lose on open
  343.         else
  344.             return GUSI_error(EISCONN);    // Got a live un', don't reconnect
  345.  
  346.     ccb     =    new TRCCB;
  347.     if (!ccb)
  348.         goto memErrCCB;
  349.  
  350.     pb        =    new DSPParamBlock;
  351.     if (!pb)
  352.         goto memErrPB;
  353.  
  354.     bufs    =    new ADSPSockBuffers;
  355.     if (!bufs)
  356.         goto memErrBufs;
  357.  
  358.     pb->ioCRefNum                        =    AppleTalkSockets.GetDSP();
  359.     pb->csCode                            =    dspInit;
  360.     pb->u.initParams.ccbPtr            =    ccb;
  361.     pb->u.initParams.userRoutine    =    nil;
  362.     pb->u.initParams.sendQSize        =    bufs->qSize;
  363.     pb->u.initParams.sendQueue        =    bufs->sendBuf;
  364.     pb->u.initParams.recvQSize        =    bufs->qSize;
  365.     pb->u.initParams.recvQueue        =    bufs->recvBuf;
  366.     pb->u.initParams.attnPtr        =    bufs->attnBuf;
  367.     pb->u.initParams.localSocket    =    socket;
  368.  
  369.     if (!PBControlSync(ParmBlkPtr(pb)))    {
  370.         socket        =    pb->u.initParams.localSocket;
  371.  
  372.         if (symaddr)
  373.             symaddr->Register(socket);
  374.  
  375.         return 0;
  376.     }
  377.  
  378.     delete bufs;
  379.     bufs    =    nil;
  380. memErrBufs:
  381.     delete pb;
  382.     pb        =    nil;
  383. memErrPB:
  384.     delete ccb;
  385.     ccb    =    nil;
  386. memErrCCB:
  387.     return GUSI_error(ENOMEM);
  388. }
  389.  
  390. void ADSPSocket::UnInit(Boolean abort)
  391. {
  392.     if (ccb && pb)    {
  393.         pb->csCode                    =    bufs ? dspRemove : dspCLRemove;
  394.         pb->u.closeParams.abort    =    abort;
  395.  
  396.         PBControlSync(ParmBlkPtr(pb));
  397.     }
  398.  
  399.     if (ccb)
  400.         delete ccb;
  401.     if (pb)
  402.         delete pb;
  403.     if (bufs)
  404.         delete bufs;
  405.     
  406.     ccb    =    nil;
  407.     pb        =    nil;
  408.     bufs    =    nil;
  409. }
  410.  
  411. int ADSPSocket::connect(void *sa_name, int)
  412. {
  413.     switch (*(short *) sa_name)    {
  414.     case AF_APPLETALK:
  415.         {
  416.             sockaddr_atlk *    addr     =    (struct sockaddr_atlk *) sa_name;
  417.             peer                            =    addr->addr;
  418.         }
  419.         break;
  420.     case ATALK_SYMADDR:
  421.         {
  422.             struct sockaddr_atlk_sym *    addr     =     (struct sockaddr_atlk_sym *) sa_name;
  423.  
  424.             if (AtlkLookup(addr->name, &peer))
  425.                 return -1;
  426.         }
  427.         break;
  428.     default:
  429.         return GUSI_error(EAFNOSUPPORT);
  430.     }
  431.  
  432.     if (Init())
  433.         return -1;
  434.  
  435.     pb->csCode                                =    dspOpen;
  436.     pb->ioCompletion                        =    nil;
  437.     pb->u.openParams.remoteAddress    =    peer;
  438.     pb->u.openParams.filterAddress    =    NoFilter;
  439.     pb->u.openParams.ocMode                =    ocRequest;
  440.     pb->u.openParams.ocInterval        =    0;
  441.     pb->u.openParams.ocMaximum            =    0;
  442.  
  443.     PBControlAsync(ParmBlkPtr(pb));
  444.  
  445.     if (nonblocking)
  446.         return GUSI_error(EINPROGRESS);
  447.  
  448.     SAFESPIN(Waiting(), SP_MISC, 0);
  449.  
  450.     if (errno)    {
  451.         UnInit(true);
  452.         
  453.         return -1;
  454.     } else if (pb->ioResult == noErr) {
  455.         return 0;
  456.     } else
  457.         return GUSI_error(ECONNREFUSED);
  458. }
  459.  
  460. Socket * ADSPSocket::accept(void * address, int * addrlen)
  461. {
  462.     ADSPSocket *    newsock;
  463.     sockaddr_atlk    addr;
  464.  
  465.     if (!pb || pb->csCode != dspCLListen)
  466.         return (Socket *) GUSI_error_nil(ENOTCONN);
  467.  
  468.     if (nonblocking && pb->ioResult == 1)
  469.         return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  470.  
  471.     SPINP(Waiting(), SP_MISC, 0);
  472.  
  473.     if (pb->ioResult)
  474.         return (Socket *) GUSI_error_nil(EFAULT);
  475.  
  476.     newsock    =    new ADSPSocket(socket);
  477.  
  478.     if (!newsock)
  479.         return (Socket *) GUSI_error_nil(ENOMEM);
  480.     if (newsock->Init())
  481.         return (Socket *) nil;
  482.  
  483.     newsock->pb->csCode                            =    dspOpen;
  484.     newsock->pb->ioCompletion                    =    nil;
  485.     newsock->pb->u.openParams                    =    pb->u.openParams;
  486.     newsock->pb->u.openParams.ocMode            =    ocAccept;
  487.     newsock->pb->u.openParams.ocInterval    =    0;
  488.     newsock->pb->u.openParams.ocMaximum        =    0;
  489.     PBControlAsync(ParmBlkPtr(newsock->pb));
  490.  
  491.     SAFESPIN(newsock->Waiting(), SP_MISC, 0);
  492.  
  493.     pb->csCode                                =    dspCLListen;
  494.     pb->ioCompletion                        =    nil;
  495.     pb->u.openParams.filterAddress    =    NoFilter;
  496.  
  497.     PBControlAsync(ParmBlkPtr(pb));
  498.  
  499.     if (errno || newsock->pb->ioResult)    {
  500.         delete newsock;
  501.  
  502.         return (Socket *) (errno ? nil : GUSI_error_nil(ECONNREFUSED));
  503.     }
  504.  
  505.     if (address && addrlen)    {
  506.         addr.family    =    AF_APPLETALK;
  507.         addr.addr    =    pb->u.openParams.remoteAddress;
  508.  
  509.         memcpy(address, &addr, *addrlen = min(*addrlen, sizeof(sockaddr_atlk)));
  510.     }
  511.  
  512.     return newsock;
  513. }
  514.  
  515. int ADSPSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int *)
  516. {
  517.     if (from)
  518.         return GUSI_error(EOPNOTSUPP);
  519.     if (flags & ~MSG_OOB)
  520.         return GUSI_error(EOPNOTSUPP);
  521.     if (!pb)
  522.         return GUSI_error(ENOTCONN);
  523.  
  524.     if (pb->csCode == dspOpen && pb->ioResult)    {
  525.         if (pb->ioResult == 1)    {
  526.             if (nonblocking)
  527.                 return GUSI_error(EWOULDBLOCK);
  528.  
  529.             SPIN(Waiting(), SP_MISC, 0);
  530.         }
  531.  
  532.         if (pb->ioResult)
  533.             return GUSI_error(ECONNREFUSED);
  534.     }
  535.  
  536.     if (flags & MSG_OOB)
  537.         if (ccb->userFlags & eAttention)    {
  538.             memcpy(Ptr(buffer), ccb->attnPtr, buflen = min(buflen, ccb->attnSize));
  539.  
  540.             ccb->userFlags ^= eAttention;
  541.  
  542.             return buflen;
  543.         } else
  544.             return GUSI_error(EINVAL);
  545.  
  546.     pb->csCode            =    dspStatus;
  547.  
  548.     PBControlSync(ParmBlkPtr(pb));
  549.  
  550.     if (!pb->u.statusParams.recvQPending)
  551.         if (nonblocking)
  552.             return GUSI_error(EWOULDBLOCK);
  553.         else if (readShutDown)
  554.             return 0;
  555.  
  556.     while (!pb->u.statusParams.recvQPending && Up()) {
  557.         SPIN(0, SP_STREAM_READ, 0);
  558.         PBControlSync(ParmBlkPtr(pb));
  559.     }
  560.  
  561.     pb->csCode                    =    dspRead;
  562.     pb->u.ioParams.reqCount    =    min(buflen, pb->u.statusParams.recvQPending);
  563.     pb->u.ioParams.dataPtr    =    (u_char *) buffer;
  564.  
  565.     if (PBControlSync(ParmBlkPtr(pb)))
  566.         readShutDown = true;
  567.  
  568.     return pb->u.ioParams.actCount;
  569. }
  570.  
  571. int ADSPSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  572. {
  573.     if (to)
  574.         return GUSI_error(EOPNOTSUPP);
  575.     if (flags & ~MSG_OOB)
  576.         return GUSI_error(EOPNOTSUPP);
  577.     if (!pb)
  578.         return GUSI_error(ENOTCONN);
  579.  
  580.     if (pb->csCode == dspOpen && (pb->ioResult || !Up()))    {
  581.         if (Waiting())    {
  582.             if (nonblocking)
  583.                 return GUSI_error(EWOULDBLOCK);
  584.  
  585.             SPIN(Waiting(), SP_MISC, 0);
  586.         }
  587.  
  588.         if (pb->ioResult)
  589.             return GUSI_error(ECONNREFUSED);
  590.     }
  591.  
  592.     if (writeShutDown)
  593.             return GUSI_error(ESHUTDOWN);
  594.  
  595.     if (flags & MSG_OOB)    {
  596.         if (buflen < 0 || buflen > 570)
  597.             return GUSI_error(EINVAL);
  598.  
  599.         pb->csCode                        =    dspAttention;
  600.         pb->u.attnParams.attnCode    =    0;
  601.         pb->u.attnParams.attnSize    =    buflen;
  602.         pb->u.attnParams.attnData    =    (unsigned char *) buffer;
  603.  
  604.         PBControlSync(ParmBlkPtr(pb));
  605.  
  606.         if (pb->ioResult)
  607.             return GUSI_error(EINVAL);
  608.         else
  609.             return buflen;
  610.     }
  611.  
  612.     if (nonblocking)    {
  613.         pb->csCode    =    dspStatus;
  614.  
  615.         PBControlSync(ParmBlkPtr(pb));
  616.  
  617.         if (!pb->u.statusParams.sendQFree)
  618.             return GUSI_error(EWOULDBLOCK);
  619.     }
  620.  
  621.     pb->csCode                    =    dspWrite;
  622.     pb->u.ioParams.reqCount    =
  623.         nonblocking
  624.             ?     min(buflen, pb->u.statusParams.sendQFree)
  625.             :    buflen;
  626.     pb->u.ioParams.dataPtr    =    (u_char *) buffer;
  627.     pb->u.ioParams.eom        =    false;
  628.     pb->u.ioParams.flush        =    true;
  629.  
  630.     PBControlAsync(ParmBlkPtr(pb));
  631.  
  632.     SPIN(Waiting(), SP_STREAM_WRITE, 0);
  633.  
  634.     if (pb->ioResult)
  635.         writeShutDown = true;
  636.  
  637.     return pb->u.ioParams.actCount;
  638. }
  639.  
  640. int ADSPSocket::shutdown(int how)
  641. {
  642.     if (how < 0 || how > 2)
  643.         return GUSI_error(EINVAL);
  644.  
  645.     if (how)
  646.         writeShutDown    =    true;
  647.     if (!(how & 1))
  648.         readShutDown    =    true;
  649.  
  650.     return 0;
  651. }
  652.  
  653. int ADSPSocket::ioctl(unsigned int request, void *argp)
  654. {
  655.     switch (request)    {
  656.     case FIONREAD:
  657.         if (!pb)
  658.             return GUSI_error(ENOTCONN);
  659.  
  660.         pb->csCode            =    dspStatus;
  661.  
  662.         PBControlSync(ParmBlkPtr(pb));
  663.  
  664.         *(unsigned long *) argp    = pb->u.statusParams.recvQPending;
  665.  
  666.         return 0;
  667.     default:
  668.         return AppleTalkSocket::ioctl(request, argp);
  669.     }
  670. }
  671.  
  672. int ADSPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  673. {
  674.     int    goodies = 0;
  675.  
  676.     if (pb) {
  677.         pb->csCode        =    dspStatus;
  678.         PBControlSync(ParmBlkPtr(pb));
  679.     }
  680.     
  681.     if (canRead)
  682.         if ( !pb || readShutDown || !Up() || pb->u.statusParams.recvQPending
  683.             ||    (pb->csCode == dspCLListen && pb->ioResult != 1)
  684.         )    {
  685.             *canRead = true;
  686.             ++goodies;
  687.         }
  688.  
  689.     if (canWrite)
  690.         if ( !pb || writeShutDown || !Up() || pb->u.statusParams.sendQFree != 0
  691.             || (pb->csCode == dspOpen && pb->ioResult != 1)
  692.         )    {
  693.             *canWrite = true;
  694.             ++goodies;
  695.         }
  696.         
  697.     if (exception && (ccb->userFlags & eAttention)) {
  698.         *exception = true;
  699.         ++goodies;
  700.     }
  701.  
  702.     return goodies;
  703. }
  704.  
  705. /********************* AppleTalkSocketDomain members **********************/
  706.  
  707. extern "C" void GUSIwithAppleTalkSockets()
  708. {
  709.     AppleTalkSockets.DontStrip();
  710. }
  711.  
  712. AppleTalkSocketDomain::AppleTalkSocketDomain()
  713.     :    SocketDomain(AF_APPLETALK)
  714. {
  715.     dspRefNum    =    0;
  716.     node.aNet    =    -1;
  717.     node.aNode    =    0;
  718.     node.aSocket=    0;
  719. }
  720.  
  721. void AppleTalkSocketDomain::DoMPPOpen()
  722. {
  723.     short    myNode;
  724.     short    myNet;
  725.  
  726.     if (AppleTalkIdentity(myNet, myNode))    {
  727.         node.aNet    =    -1;
  728.         node.aNode    =    0;
  729.         node.aSocket=    0;
  730.     } else {
  731.         node.aNet    =    myNet;
  732.         node.aNode    =    (u_char) myNode;
  733.         node.aSocket=    1;
  734.     }
  735. }
  736.  
  737. Boolean AppleTalkSocketDomain::Validate()
  738. {
  739.     if (!node.aSocket)
  740.         DoMPPOpen();
  741.  
  742.     return node.aSocket != 0;
  743. }
  744.  
  745. short    AppleTalkSocketDomain::GetDSP()
  746. {
  747.     if (!dspRefNum)
  748.         if (OpenDriver("\p.DSP", &dspRefNum))
  749.             dspRefNum    =    0;
  750.  
  751.     return dspRefNum;
  752. }
  753.  
  754. Socket * AppleTalkSocketDomain::socket(int type, short)
  755. {
  756.     AppleTalkSocket * sock    =    nil;
  757.  
  758.     errno    =    0;
  759.  
  760.     if (!Validate())
  761.         GUSI_error(ENETDOWN);
  762.     else
  763.         switch (type)    {
  764.         case SOCK_STREAM:
  765.             sock = new ADSPSocket();
  766.             break;
  767.         default:
  768.             GUSI_error(ESOCKTNOSUPPORT);
  769.         }
  770.  
  771.     if (sock && errno)    {
  772.         delete sock;
  773.  
  774.         return nil;
  775.     } else
  776.         return sock;
  777. }
  778.  
  779. int AppleTalkSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  780. {
  781.     sa_constr_atlk *     constr = (sa_constr_atlk *) constraint;
  782.     Point                    where;
  783.     NBPReply                reply;
  784.     sockaddr_atlk        addr;
  785.     char *                end;
  786.     Str255                promp;
  787.     NLType                dummy;
  788.  
  789.     if (!hasStdNBP)
  790.         return GUSI_error(EOPNOTSUPP);
  791.  
  792.     if (!Validate())
  793.         return GUSI_error(ENETDOWN);
  794.  
  795.     if (flags & (CHOOSE_NEW | CHOOSE_DIR))
  796.         return GUSI_error(EINVAL);
  797.         
  798.     SetPt(&where, 100, 100);
  799.  
  800.     memset(&reply.theEntity, 0, sizeof(EntityName));
  801.     memcpy(&reply.theEntity.zoneStr, "\p*", 2);
  802.  
  803.     end         =     (char *) memccpy(promp+1, prompt, 0, 254);
  804.     promp[0]    =    end-(char *)promp-2;
  805.  
  806.     if (
  807.         StandardNBP(
  808.             where,
  809.             promp,
  810.             constr ? constr->numTypes : -1,
  811.             constr ? constr->types : dummy,
  812.             (NameFilterProcPtr) nil,
  813.             (ZoneFilterProcPtr) nil,
  814.             (DlgHookProcPtr) nil,
  815.             &reply)
  816.         != nlOk
  817.     )
  818.         return GUSI_error(EINTR);
  819.  
  820.     addr.family    =    AF_APPLETALK;
  821.     addr.addr    =     reply.theAddr;
  822.  
  823.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(sockaddr_atlk)));
  824.  
  825.     return 0;
  826. }
  827.  
  828. /*********************** AtlkSymAddr members ************************/
  829.  
  830. static int EntityLen(const EntityName & name)
  831. {
  832.     Ptr    nm    =    Ptr(&name);
  833.     int    l1    =    *nm+1;
  834.     nm += l1;
  835.     int    l2    =    *nm+1;
  836.     nm += l2;
  837.     int    l3    =    *nm+1;
  838.  
  839.     return l1+l2+l3;
  840. }
  841.  
  842. AtlkSymAddr::AtlkSymAddr(const EntityName & name)
  843. {
  844.     int                len    =    EntityLen(name);
  845.  
  846.     errno = 0;
  847.  
  848.     if (!AppleTalkSockets.Validate())    {
  849.         GUSI_error(ENETDOWN);
  850.  
  851.         return;
  852.     }
  853.  
  854.     nte    =    (NTE *) NewPtr(9+len);
  855.     legit    =    false;
  856.  
  857.     if (!nte)    {
  858.         GUSI_error(ENOMEM);
  859.  
  860.         return;
  861.     }
  862.  
  863.     nte->next            =    nil;
  864.     memcpy(&nte->name, &name, len);
  865. }
  866.  
  867. void AtlkSymAddr::Register(u_char socket)
  868. {
  869.     MPPParamBlock    mpp;
  870.  
  871.     errno = 0;
  872.  
  873.     nte->addr.aSocket    =    socket;
  874.  
  875.     mpp.NBPinterval    =    8;
  876.     mpp.NBPcount        =    3;
  877.     mpp.NBPntQElPtr    =    Ptr(nte);
  878.     mpp.NBPverifyFlag    =    true;
  879.     PRegisterName(&mpp, false);
  880.  
  881.     if (mpp.MPPioResult)    {
  882.         DisposPtr(Ptr(nte));
  883.  
  884.         GUSI_error((mpp.MPPioResult == nbpDuplicate) ? EADDRINUSE : EFAULT);
  885.     } else
  886.         legit    =    true;
  887. }
  888.  
  889. AtlkSymAddr::~AtlkSymAddr()
  890. {
  891.     if (nte)    {
  892.         if (legit) {
  893.             MPPParamBlock    mpp;
  894.  
  895.             mpp.NBPentityPtr    =    Ptr(&nte->name);
  896.             PRemoveName(&mpp, false);
  897.         }
  898.  
  899.         DisposPtr(Ptr(nte));
  900.     }
  901. }
  902.  
  903. static int AtlkLookup(const EntityName & name, AddrBlock * addr)
  904. {
  905.     EntityName        ent;
  906.     char                found[256];
  907.     MPPParamBlock    mpp;
  908.  
  909.     mpp.NBPinterval        =    8;
  910.     mpp.NBPcount            =    3;
  911.     mpp.NBPentityPtr        =    Ptr(&name);
  912.     mpp.NBPretBuffPtr        =    found;
  913.     mpp.NBPretBuffSize    =    256;
  914.     mpp.NBPmaxToGet        =    1;
  915.     PLookupName(&mpp, false);
  916.     if (!mpp.MPPioResult)
  917.         NBPExtract(found, mpp.NBPnumGotten, 1, &ent, addr);
  918.  
  919.     if (mpp.MPPioResult)
  920.         return GUSI_error(EADDRNOTAVAIL);
  921.  
  922.     return 0;
  923. }
  924.